package main

import (
	"encoding/json"
	"github.com/gorilla/websocket"
)

type Message struct {
	Sender    string `json:"sender,omitempty"`    //发送者
	Recipient string `json:"recipient,omitempty"` //接收者
	Content   string `json:"content,omitempty"`   //消息内容
}

type Client struct {
	id     string          //客户端的唯一标识符
	socket *websocket.Conn //与客户端的 WebSocket 连接
	send   chan []byte     //一个通道，用于向客户端发送消息。
}

type ClientManager struct {
	clients    map[*Client]bool //一个映射，保存所有连接的客户端
	broadcast  chan []byte      //一个通道，用于广播消息到所有客户端
	register   chan *Client     //一个通道，用于注册新连接的客户端
	unregister chan *Client     //一个通道，用于注销断开连接的客户端
}

/*
*
创建一个全局的 ClientManager 实例 manager，用于管理所有客户端连接。
*/
var manager = ClientManager{
	broadcast:  make(chan []byte),
	register:   make(chan *Client),
	unregister: make(chan *Client),
	clients:    make(map[*Client]bool),
}

/*
*
start 方法是 ClientManager 的主循环，处理客户端注册、注销和广播消息：
register：当有新客户端连接时，添加到 clients 中，并广播消息通知其他客户端。
unregister：当客户端断开连接时，移除 clients 中，并通知其他客户端。
broadcast：将收到的消息广播给所有连接的客户端。
*/
func (manager *ClientManager) start() {
	for {
		select {
		case conn := <-manager.register:
			manager.clients[conn] = true
			jsonMessage, _ := json.Marshal(&Message{Content: "/A new socket has connected."})
			manager.send(jsonMessage, conn)
		case conn := <-manager.unregister:
			if _, ok := manager.clients[conn]; ok {
				close(conn.send)
				delete(manager.clients, conn)
				jsonMessage, _ := json.Marshal(&Message{Content: "/A socket has disconnected."})
				manager.send(jsonMessage, conn)
			}
		case message := <-manager.broadcast:
			for conn := range manager.clients {
				select {
				case conn.send <- message:
				default:
					close(conn.send)
					delete(manager.clients, conn)
				}
			}
		}
	}
}

/*
*
send 方法将消息发送给所有客户端，除了指定的 ignore 客户端。
*/
func (manager *ClientManager) send(message []byte, ignore *Client) {
	for conn := range manager.clients {
		if conn != ignore {
			conn.send <- message
		}
	}
}

/*
*
read 方法从客户端读取消息并将其广播到其他客户端。如果读取过程中发生错误（例如客户端断开连接），则注销客户端。
*/
func (c *Client) read() {
	defer func() {
		manager.unregister <- c
		c.socket.Close()
	}()

	for {
		_, message, err := c.socket.ReadMessage()
		if err != nil {
			manager.unregister <- c
			c.socket.Close()
			break
		}
		jsonMessage, _ := json.Marshal(&Message{Sender: c.id, Content: string(message)})
		manager.broadcast <- jsonMessage
	}
}

/*
*
write 方法将消息写入客户端。如果客户端关闭连接，发送关闭消息并返回。
*/
func (c *Client) write() {
	defer func() {
		c.socket.Close()
	}()

	for {
		select {
		case message, ok := <-c.send:
			if !ok {
				c.socket.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			c.socket.WriteMessage(websocket.TextMessage, message)
		}
	}
}
